﻿using Futajma.MigrationStudio.DataDefinition.Dialog;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Futajma.MigrationStudio.DataDefinition
{

    public class SearchReplaceResult
    {
        public TreeNode Node { get; set; }
        public string ReplacedUrl { get; set; }
        public string OriginalUrl { get; set; }
    }

    [ObfuscationAttribute(Exclude = true, ApplyToMembers = true)]
    public class SearchReplacePair
    {
        [XmlAttribute("SearchCharacter")]
        public string SearchCharacter { get; set; }
        [XmlAttribute("ReplaceCharacter")]
        public string ReplaceCharacter { get; set; }
    }

    [ObfuscationAttribute(Exclude = true, ApplyToMembers = true)]
    public class GovernanceData
    {
        #region Content Reorganisation Rules
        //public bool AllowExcludeItems { get; set; }
        //public bool AllowExcludeItemsOnlyByGovernanceIssue { get; set; }

        //public bool AllowExcludeFolders { get; set; }
        //public bool AllowExcludeFoldersOnlyByGovernanceIssue { get; set; }

        //public bool AllowExcludeLibraries { get; set; }
        //public bool AllowExcludeLibrariesOnlyByGovernanceIssue { get; set; }

        //public bool AllowExcludeSites { get; set; }
        //public bool AllowExcludeSitesOnlyByGovernanceIssue { get; set; }

        //public bool AllowExcludeSiteCollections { get; set; }
        //public bool AllowExcludeSiteCollectionsOnlyByGovernanceIssue { get; set; }

        public bool AllowMoveItems { get; set; }
        public bool AllowMoveItemsOnlyByGovernanceIssue { get; set; }

        public bool AllowMoveFolders { get; set; }
        public bool AllowMoveFoldersOnlyByGovernanceIssue { get; set; }

        public bool AllowMoveLibraries { get; set; }
        public bool AllowMoveLibrariesOnlyByGovernanceIssue { get; set; }

        public bool AllowMoveSites { get; set; }
        public bool AllowMoveSitesOnlyByGovernanceIssue { get; set; }

        public bool AllowMoveSiteCollections { get; set; }
        public bool AllowMoveSiteCollectionsOnlyByGovernanceIssue { get; set; }

        public bool AllowCreateSiteFromDragAndDrop { get; set; }
        public bool AllowCreateLibraryFromDragAndDrop { get; set; }
        public bool AllowCreateFolderFromDragAndDrop { get; set; }
        public bool AllowCreateSiteCollectionFromDragAndDrop { get; set; }

        #endregion

        #region GovernanceLimitations
        public int ListItemThreshold { get; set; }

        public int FileSizeLimit { get; set; }

        public long SiteCollectionSizeLimit { get; set; }

        public int PathLenghtLimit { get; set; }

        public int DefaultPlattformUrlPathLength { get; set; }

        public bool ExcludeSiteCollectionNamesInPathCalulation { get; set; }

        public int MaxFilePathLength { get; set; }

        public string[] ForbiddenFileExtensions = { ".ade",".adp",".app",".asp",".bas",".bat",".cer",".chm", "cmd",".cnt",".com",".cpl",".crt",".csh",".der",".exe",".fxp",".gadget",
            ".grp",".hlp",".hpj",".hta",".inf",".ins",".isp",".its",".jar",".js",".jse",".ksh",".lnk",".mad",".maf",".mag",".mam",".maq",
            ".mar",".mas",".mat",".mau",".mav",".maw",".mcf",".mda",".mdb",".mde",".mdt",".mdw",".mdz",".msc",".msh",".msh1",".msh2",".mshxml",
            ".msh1xml",".msh2xml",".msi",".msp",".mst",".ops",".osd",".pcd",".pif",".pl",".plg",".prf",".prg",".ps1",".ps1xml",".ps2",".ps2xml",
            ".psc1",".psc2",".pst",".reg",".scf",".scr",".sct",".shb",".shs",".tmp",".url",".vb",".vbe",".vbp",".vbs",".vsmacros",".vsw",
            ".ws",".wsc",".wsf",".wsh",".xbap",".xnk" };

        public char[] ForbiddenFileAndFolderPathNameCharacters = { '"', '#', '%', '&', '*', ':', '<', '>', '?', '\\', '/', '{', '|', '}', '~' };
        public char[] ForbiddenSiteNameCharacters = { '|', '#', '{', '}', '%', '&', '<', '>', '"', '~', '+', '\\', '/', ':', '*', '?' };
        public char[] ForbiddenSiteCollectionNameCharacters = { '|', '#', '{', '}', '%', '&', '<', '>', '"', '~', '+', '\\', '*', '?' };
        public string[] ForbiddenFolderExtensions = {".files", "_files" , "-Dateien" , "_fichiers" , "_bestanden" , "_file" ,"_archivos" ,"-filer","_tiedostot" ,"_pliki" ,"_soubory" ,"_elemei" ,
                                                        "_arquivos" ,"_dosyalar" ,"_datoteke" ,"_fitxers","_failid","_fails" ,"_bylos" ,"_fajlovi","_fitxategiak"};

        //public char[] SearchForReplaceCharacters = { '~', '!', '@', '#', '$', '%', '^', '&', '*', '{', '}', '[', ']', '=', '+', '\\', ':', '"', '\'', '|', '<', '>', ',', '?', '/', '.', ';' };
        //public string[] ReplaceForReplaceCharacters = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" };

        [XmlArray("SearchReplacePairs")]
        [XmlArrayItem("SearchReplacePair")]
        public List<SearchReplacePair> SearchAndReplaceCharacters = new List<SearchReplacePair>();

        [XmlArray("ReplaceRegularExpressionPairs")]
        [XmlArrayItem("ReplaceRegularExpressionPair")]
        public List<SearchReplacePair> ReplaceRegularExpressionPairs = new List<SearchReplacePair>();

        #endregion

        #region Load/Save Methods
        public static GovernanceData LoadXml(Stream stream)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(GovernanceData));
            var governanceData = (GovernanceData)(serializer.Deserialize(stream));
            return governanceData;
        }

        public static StringBuilder Save(GovernanceData governanceData)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = new UnicodeEncoding(false, false);
            settings.Indent = true;
            settings.OmitXmlDeclaration = true;

            var serializer = new XmlSerializer(typeof(GovernanceData));
            StringBuilder sb = new StringBuilder();
            using (XmlWriter writer = XmlWriter.Create(sb, settings))
            {
                serializer.Serialize(writer, governanceData);
            }
            return sb;
        }
        #endregion

        #region MemberVariables
        Dictionary<string, List<TreeNode>> _flattenFileList = new Dictionary<string, List<TreeNode>>();
        #endregion

        #region Constructor
        public GovernanceData()
        {
            #region Preset Content Reorganisation values
            //AllowExcludeItems = false;
            //AllowExcludeItemsOnlyByGovernanceIssue = true;
            //AllowExcludeFolders = false;
            //AllowExcludeFoldersOnlyByGovernanceIssue = true;
            //AllowExcludeLibraries = true;
            //AllowExcludeLibrariesOnlyByGovernanceIssue = true;
            //AllowExcludeSites = true;
            //AllowExcludeSitesOnlyByGovernanceIssue = true;
            //AllowExcludeSiteCollections = true;
            //AllowExcludeSiteCollectionsOnlyByGovernanceIssue = true;

            AllowCreateSiteCollectionFromDragAndDrop = true;
            AllowCreateSiteFromDragAndDrop = true;
            AllowCreateLibraryFromDragAndDrop = true;
            AllowCreateFolderFromDragAndDrop = true;

            AllowMoveItems = false;
            AllowMoveItemsOnlyByGovernanceIssue = true;
            AllowMoveFolders = false;
            AllowMoveFoldersOnlyByGovernanceIssue = true;
            AllowMoveLibraries = true;
            AllowMoveLibrariesOnlyByGovernanceIssue = true;
            AllowMoveSites = true;
            AllowMoveSitesOnlyByGovernanceIssue = true;
            AllowMoveSiteCollections = true;
            AllowMoveSiteCollectionsOnlyByGovernanceIssue = true;
            #endregion

            #region Preset Governance Limitations
            ListItemThreshold = 5000;
            FileSizeLimit = 262144000; //(250MB)
            SiteCollectionSizeLimit = 53687091200; //(50GB)
            DefaultPlattformUrlPathLength = 50;
            PathLenghtLimit = 260;
            ExcludeSiteCollectionNamesInPathCalulation = true;
            MaxFilePathLength = 128;
            #endregion

            #region PreSet IllegalCharacterSearchAndReplace
            //SearchAndReplaceCharacters = new List<SearchReplacePair> { 
            //new SearchReplacePair() { SearchCharacter = "~", ReplaceCharacter = "_" }, 
            //new SearchReplacePair() { SearchCharacter = "\"", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "#", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "%", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "&", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "*", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = ":", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "<", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = ">", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "?", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "/", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "\\", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "{", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "|", ReplaceCharacter = "_" },
            //new SearchReplacePair() { SearchCharacter = "}", ReplaceCharacter = "_" },
            //};
            #endregion

        }

        public GovernanceData(bool loadDefault)
            : this()
        {
            #region PreSet IllegalCharacterSearchAndReplace
            SearchAndReplaceCharacters = new List<SearchReplacePair> { 
            new SearchReplacePair() { SearchCharacter = "~", ReplaceCharacter = "_" }, 
            new SearchReplacePair() { SearchCharacter = "\"", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "#", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "%", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "&", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "*", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = ":", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "<", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = ">", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "?", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "/", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "\\", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "{", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "|", ReplaceCharacter = "_" },
            new SearchReplacePair() { SearchCharacter = "}", ReplaceCharacter = "_" },
            };
            #endregion

        }

        #endregion

        #region Report generation

        public void CreateViolationExcelReport(TreeView tree, string filename)
        {
            var dataList = new List<string>();
            foreach (TreeNode node in tree.Nodes)
            {
                ReportNode(node, dataList);
            }

            File.WriteAllLines(filename, dataList.ToArray(), Encoding.Unicode);

        }

        private void ReportNode(TreeNode node, List<string> dataList)
        {
            DataNode data = node.Tag as DataNode;

            StringBuilder sb = new StringBuilder();

            if (data.GovernanceViolation)
            {
                dataList.Add(GetViolationText(data, ItemOperation.GeneratePath(node, false)));
            }
            if (data.SharePointStructureViolation)
            {
                dataList.Add(string.Format("{0};{1};", ItemOperation.GeneratePath(node, false), "Structure of the content is not supported in SharePoint"));
            }

            foreach (TreeNode child in node.Nodes)
            {
                ReportNode(child, dataList);
            }
        }

        //string GetPathToRoot(TreeNode node)
        //{
        //    string path = "";
        //    var runner = node;
        //    while (runner != null)
        //    {
        //        path = string.Format("{0}/{1}", runner.Text, path);
        //        runner = runner.Parent;
        //    }
        //    return path;
        //}



        string GetViolationText(DataNode dataNode, string path)
        {
            var sb = new StringBuilder();
            sb.AppendFormat("{0};", path);

            if ((dataNode.ViolationType & ViolationType.ItemSizeExceeded) != 0)
            {
                
                sb.AppendFormat("{0}; {1}", "The size of the item or document is exceeded", DataComplexityCalculation.ToFuzzyByteString(dataNode.FileSize));
            }

            if ((dataNode.ViolationType & ViolationType.ItemThresholdExceeded) != 0)
            {
                sb.AppendFormat("{0}; {1};", "The maximum item or document threshold of the list is exceeded", dataNode.ItemCount);
            }

            if ((dataNode.ViolationType & ViolationType.PathLengthExceeded) != 0)
            {
                sb.AppendFormat("{0}; {1};", "The length of the item or document path is exceeded", dataNode.PathLength);
            }

            if ((dataNode.ViolationType & ViolationType.FileNameDuplicated) != 0)
            {
                sb.AppendFormat("{0}; {1};", "More than one file with identical path", dataNode.DuplicatedFilenameViolationCount);
            }

            if ((dataNode.ViolationType & ViolationType.FilePathNameLengthExceeds) != 0)
            {
                sb.AppendFormat("{0}; {1};", "The length of the item or document title is exceeded", dataNode.EncodedTitle.Length);
            }

            if ((dataNode.ViolationType & ViolationType.IllegalFileExtensionDetected) != 0)
            {
                sb.AppendFormat("{0};", "The type of file is restricted.");
            }

            if ((dataNode.ViolationType & ViolationType.IllegalFileAndFolderCharacterDetected) != 0 ||
                (dataNode.ViolationType & ViolationType.IllegalSiteAndSubsiteCharacterDetected) != 0)
            {
                sb.AppendFormat("{0};", "The path or filename conatin unsupported characters");
            }
            return sb.ToString();
        }

        #endregion

        #region Methods

        public void ShowSearchAndReplaceDialog(TreeNode targetNode)
        {
            var dlg = new SearchAndReplaceCharacters(this, targetNode);

            dlg.ShowDialog();
        }

        public void SaveSearchReplaceUnsupportedCharacterReport(string filename, List<SearchReplaceResult> modifiedNodes)
        {
            XElement el = new XElement("Report");

            var docs = new XElement("SearchAndReplaceCharacters");
            el.Add(docs);

            foreach (var pair in SearchAndReplaceCharacters)
            {
                XElement item = new XElement("SearchReplacePair");
                item.Add(new XAttribute("SearchCharacter", pair.SearchCharacter));
                item.Add(new XAttribute("ReplaceCharacter", pair.ReplaceCharacter));
                docs.Add(item);
            }

            docs = new XElement("Replacements");
            el.Add(docs);

            foreach (var rpItem in modifiedNodes)
            {
                DataNode data = rpItem.Node.Tag as DataNode;
                XElement item = new XElement("Item");
                item.Add(new XAttribute("sU", rpItem.OriginalUrl));
                item.Add(new XAttribute("tU", rpItem.ReplacedUrl));
                item.Add(new XAttribute("sId", data != null && data.SourceId != null ? data.SourceId : "unknown"));
                docs.Add(item);
            }
            el.Save(filename);
        }

        public void SearchReplaceUnsupportedCharacters(TreeNode node, List<SearchReplaceResult> modifiedNodes, SharePointType sharePointType, bool tryRun = false)
        {
            DataNode data = node.Tag as DataNode;

            if (sharePointType == data.SharePointType && !data.CommitedItem && (data.SharePointType == SharePointType.Document ||
                data.SharePointType == SharePointType.Item ||
                data.SharePointType == SharePointType.Folder))
            {

                var test = new StringBuilder(data.Title);
                SearchAndReplaceCharacters.ForEach(sp => test = test.Replace(sp.SearchCharacter, sp.ReplaceCharacter));
                var newTitle = test.ToString();

                if (newTitle != node.Text)
                {
                    if (tryRun)
                    {
                        //node.Text = data.Title = newTitle;
                        modifiedNodes.Add(new SearchReplaceResult() { Node = node, OriginalUrl = node.Text, ReplacedUrl = newTitle });
                    }
                    else
                    {
                        modifiedNodes.Add(new SearchReplaceResult() { Node = node, OriginalUrl = node.Text, ReplacedUrl = newTitle });
                        node.Text = data.Title = newTitle;
                    }
                }

            }

            foreach (TreeNode child in node.Nodes)
            {
                SearchReplaceUnsupportedCharacters(child, modifiedNodes, sharePointType, tryRun);
            }
        }

        public void SearchReplaceRegularExpression(TreeNode node, List<SearchReplaceResult> modifiedNodes, SharePointType sharePointType, bool tryRun = false)
        {
            DataNode data = node.Tag as DataNode;

            if (sharePointType == data.SharePointType && !data.CommitedItem && (data.SharePointType == SharePointType.Document ||
                data.SharePointType == SharePointType.Item ||
                data.SharePointType == SharePointType.Folder))
            {
                string newTitle = data.Title;
                ReplaceRegularExpressionPairs.ForEach(sp => newTitle = Regex.Replace(newTitle, sp.SearchCharacter, sp.ReplaceCharacter));

                //var test = new StringBuilder(data.Title);
                //SearchAndReplaceCharacters.ForEach(sp => test = test.Replace(sp.SearchCharacter, sp.ReplaceCharacter));
                //var newTitle = Regex.Replace(data.Title, regexPattern, regexReplacement);

                if (newTitle != node.Text)
                {
                    if (tryRun)
                    {
                        //node.Text = data.Title = newTitle;
                        modifiedNodes.Add(new SearchReplaceResult() { Node = node, OriginalUrl = node.Text, ReplacedUrl = newTitle });
                    }
                    else
                    {
                        modifiedNodes.Add(new SearchReplaceResult() { Node = node, OriginalUrl = node.Text, ReplacedUrl = newTitle });
                        node.Text = data.Title = newTitle;
                    }
                }
            }

            foreach (TreeNode child in node.Nodes)
            {
                SearchReplaceRegularExpression(child, modifiedNodes, sharePointType, tryRun);
            }

        }

        public void SearchReplaceRegularExpression(TreeNode node, List<SearchReplaceResult> modifiedNodes, SharePointType sharePointType, string regexPattern, string regexReplacement, bool tryRun = false)
        {
            DataNode data = node.Tag as DataNode;

            if (sharePointType == data.SharePointType && !data.CommitedItem && (data.SharePointType == SharePointType.Document ||
                data.SharePointType == SharePointType.Item ||
                data.SharePointType == SharePointType.Folder))
            {

                //var test = new StringBuilder(data.Title);
                //SearchAndReplaceCharacters.ForEach(sp => test = test.Replace(sp.SearchCharacter, sp.ReplaceCharacter));
                var newTitle = Regex.Replace(data.Title, regexPattern, regexReplacement);

                if (newTitle != node.Text)
                {
                    if (tryRun)
                    {
                        //node.Text = data.Title = newTitle;
                        modifiedNodes.Add(new SearchReplaceResult() { Node = node, OriginalUrl = node.Text, ReplacedUrl = newTitle });
                    }
                    else
                    {
                        modifiedNodes.Add(new SearchReplaceResult() { Node = node, OriginalUrl = node.Text, ReplacedUrl = newTitle });
                        node.Text = data.Title = newTitle;
                    }
                }
            }

            foreach (TreeNode child in node.Nodes)
            {
                SearchReplaceRegularExpression(child, modifiedNodes, sharePointType, regexPattern, regexReplacement, tryRun);
            }

        }

        public bool IsTitleEditEnabled(DataNode data)
        {
            //return string.IsNullOrEmpty(data.SourceId) && !data.CommitedItem;
            return !data.CommitedItem;
        }

        public bool IsNameEditEnabled(DataNode data)
        {
            //return string.IsNullOrEmpty(data.SourceId) && !data.CommitedItem;

            if (data.CommitedItem)
            {
                return false;
            }
            else
            {
                return data.SharePointType == SharePointType.SiteCollection ||
                    data.SharePointType == SharePointType.Site ||
                    data.SharePointType == SharePointType.DocLibrary;
            }
        }

        public bool IsMoveableToTarget(DataNode source, DataNode target)
        {
            if (target.SharePointType == SharePointType.Application && !AllowCreateSiteCollectionFromDragAndDrop)
            {
                return false;
            }

            if (target.SharePointType == SharePointType.SiteCollection && !AllowCreateSiteFromDragAndDrop)
            {
                return false;
            }

            if (target.SharePointType == SharePointType.Site && !AllowCreateLibraryFromDragAndDrop)
            {
                return false;
            }

            if (target.SharePointType == SharePointType.DocLibrary && !AllowCreateFolderFromDragAndDrop)
            {
                return false;
            }

            if (target.SharePointType == SharePointType.Document)
            {
                return false;
            }

            return true;
        }

        public bool IsNodeMovable(DataNode node)
        {
            bool ret = false;
            switch (node.SharePointType)
            {
                case SharePointType.Application:
                    ret = false;
                    break;
                case SharePointType.SiteCollection:
                    ret = AllowMoveSiteCollections || AllowMoveSiteCollectionsOnlyByGovernanceIssue && node.GovernanceViolation;
                    break;
                case SharePointType.Site:
                    ret = AllowMoveSites || AllowMoveSitesOnlyByGovernanceIssue && node.GovernanceViolation;
                    break;
                case SharePointType.DocLibrary:
                    ret = AllowMoveLibraries || AllowMoveLibrariesOnlyByGovernanceIssue && node.GovernanceViolation;
                    break;
                case SharePointType.Folder:
                    ret = AllowMoveFolders || AllowMoveFoldersOnlyByGovernanceIssue && node.GovernanceViolation;
                    break;
                case SharePointType.Item:
                case SharePointType.Document:
                    ret = AllowMoveItems || AllowMoveItemsOnlyByGovernanceIssue && node.GovernanceViolation;
                    break;
            }
            return ret;
        }

        public void ResetGovernanceCheck(TreeView treeView, int currentProjectVersion)
        {
            foreach (TreeNode node in treeView.Nodes)
            {
                //RecoloringTree(node);
                ResetViolationChecks(node);
                ItemOperation.SetItemColorForChilds(node, true, currentProjectVersion);
            }
        }

        public void CheckGovernanceVoilations(TreeView treeView, int currentProjectVersion)
        {
            foreach (TreeNode node in treeView.Nodes)
            {
                ResetViolationChecks(node);
                CalculateItemThresholdViolation(node);
                CalculateItemSizeExceededViolation(node);
                CalculatePathLengthExceededViolation(node, DefaultPlattformUrlPathLength, false);
                CalculateDuplicatedFileNames(node);
                CheckFilePathLengthExceedViolation(node);
                CheckFileExtensionExceedViolation(node);
                CheckIllegalCharactersViolation(node);
                SetViolationStates(node);
                ItemOperation.SetItemColorForChilds(node, true, currentProjectVersion);
            }
        }

        private void CheckIllegalCharactersViolation(TreeNode node)
        {
            var data = node.Tag as DataNode;

            if (data.SharePointType == SharePointType.Document ||
                data.SharePointType == SharePointType.Folder)
            {

                if (data.Title.IndexOfAny(ForbiddenFileAndFolderPathNameCharacters) != -1 ||
                    data.Title.IndexOf("..") > 0 ||
                    data.Title.EndsWith(".") ||
                    data.Title.StartsWith(".") ||
                    data.Title.StartsWith("_"))
                {
                    data.ViolationType |= ViolationType.IllegalFileAndFolderCharacterDetected;
                    data.GovernanceViolation = true;
                }
            }

            if (data.SharePointType == SharePointType.Site ||
                data.SharePointType == SharePointType.DocLibrary)
            {
                var name = string.IsNullOrEmpty(data.TargetPath) ? data.Title : data.TargetPath;
                //var results = Array.FindAll(ForbiddenSiteNameCharacters, s => s.Equals(data.Title));

                if (name.IndexOfAny(ForbiddenSiteNameCharacters) != -1 ||
                    name.IndexOf("..") > 0 ||
                    name.EndsWith(".") ||
                    name.StartsWith(".") ||
                    name.StartsWith("_"))
                {
                    data.ViolationType |= ViolationType.IllegalSiteAndSubsiteCharacterDetected;
                    data.GovernanceViolation = true;
                }
            }

            if (data.SharePointType == SharePointType.SiteCollection)
            {
                var name = string.IsNullOrEmpty(data.TargetPath) ? data.Title : data.TargetPath;
                //var results = Array.FindAll(ForbiddenSiteNameCharacters, s => s.Equals(data.Title));

                if (name.IndexOfAny(ForbiddenSiteCollectionNameCharacters) != -1 ||
                    name.IndexOf("..") > 0 ||
                    name.EndsWith(".") ||
                    name.StartsWith(".") ||
                    name.StartsWith("_"))
                {
                    data.ViolationType |= ViolationType.IllegalSiteAndSubsiteCharacterDetected;
                    data.GovernanceViolation = true;
                }

            }

            foreach (TreeNode child in node.Nodes)
            {
                CheckIllegalCharactersViolation(child);
            }
        }

        private void CheckFileExtensionExceedViolation(TreeNode node)
        {
            var data = node.Tag as DataNode;

            if (data.SharePointType == SharePointType.Document)
            {
                try
                {
                    var ext = Path.GetExtension(data.Title);

                    var results = Array.FindAll(ForbiddenFileExtensions, s => s.Equals(ext, StringComparison.InvariantCultureIgnoreCase));

                    if (results != null && results.Count() > 0)
                    {
                        data.ViolationType |= ViolationType.IllegalFileExtensionDetected;
                        data.GovernanceViolation = true;
                    }
                }
                catch (ArgumentException)
                {
                    data.ViolationType |= ViolationType.IllegalFileAndFolderCharacterDetected;
                    data.GovernanceViolation = true;
                }
            }

            foreach (TreeNode child in node.Nodes)
            {
                CheckFileExtensionExceedViolation(child);
            }
        }

        private void CheckFilePathLengthExceedViolation(TreeNode node)
        {
            var data = node.Tag as DataNode;

            if (data.SharePointType == SharePointType.Document ||
                data.SharePointType == SharePointType.Item)
            {
                // a space is 3 carachters wide
                if (data.Title.Replace(" ", "%20").Length > MaxFilePathLength)
                {
                    data.ViolationType |= ViolationType.FilePathNameLengthExceeds;
                    data.GovernanceViolation = true;
                }
            }

            foreach (TreeNode child in node.Nodes)
            {
                CheckFilePathLengthExceedViolation(child);
            }
        }

        #endregion

        #region Private Methods

        #region Duplicated file names
        private void CalculateDuplicatedFileNames(TreeNode node)
        {
            var mainData = node.Tag as DataNode;

            ProcessTreeNode(node, false);
            foreach (var key in _flattenFileList.Keys)
            {
                var list = _flattenFileList[key];

                if (list.Count > 1)
                {
                    foreach (var child in list)
                    {
                        var data = child.Tag as DataNode;

                        data.GovernanceViolation = true;
                        data.DuplicatedFilenameViolationCount = list.Count;
                        data.ViolationType |= ViolationType.FileNameDuplicated;
                    }
                }
            }

            //var mainData = node.Tag as DataNode;
            mainData.DuplicatedFilenameViolationCount = CalculateDuplicatedFilenameCount(node);

        }

        private long CalculateDuplicatedFilenameCount(TreeNode node)
        {
            long value = 0;

            #region Recursive tree iteration
            foreach (TreeNode child in node.Nodes)
            {
                value += CalculateDuplicatedFilenameCount(child);
            }
            DataNode currDataNode = node.Tag as DataNode;

            if (currDataNode.SharePointType != SharePointType.Application && (value > 0 || currDataNode.DuplicatedFilenameViolationCount > 0))
            {
                currDataNode.ViolationType |= ViolationType.FileNameDuplicated;
                value++;
            }

            return value;
            #endregion

        }

        private void ProcessTreeNode(TreeNode node, bool flattenStructure)
        {
            var data = node.Tag as DataNode;

            if (data.SharePointType == SharePointType.DocLibrary)
            {
                flattenStructure = data.RemoveFolderStructure;
            }

            if (data.SharePointType == SharePointType.Item ||
                data.SharePointType == SharePointType.Document ||
                (data.SharePointType == SharePointType.Folder && !flattenStructure) ||
                data.SharePointType == SharePointType.DocLibrary ||
                data.SharePointType == SharePointType.Site ||
                data.SharePointType == SharePointType.SiteCollection)
            {
                var targetPath = GeneratePath(node, flattenStructure).ToLower();
                //var sourceId = string.IsNullOrEmpty(data.SourceId) ? targetPath : data.SourceId;               

                if (_flattenFileList.ContainsKey(targetPath))
                {
                    _flattenFileList[targetPath].Add(node);
                }
                else
                {
                    var nodes = new List<TreeNode>();
                    nodes.Add(node);
                    _flattenFileList.Add(targetPath, nodes);
                }
            }

            foreach (TreeNode child in node.Nodes)
            {
                ProcessTreeNode(child, flattenStructure);
            }
        }

        private string GeneratePath(TreeNode node, bool flattenStructure)
        {
            var data = node.Tag as DataNode;

            if (node.Parent != null)
            {
                if (flattenStructure)
                {
                    if (data.SharePointType == SharePointType.Folder)
                    {
                        return GeneratePath(node.Parent, flattenStructure);
                    }
                }

                if (data.SharePointType == SharePointType.SiteCollection && !string.IsNullOrEmpty(data.TargetPath))
                {
                    return data.TargetPath;
                    //return string.Format("{0}/{1}", data.TargetPath, node.Text);
                }
                else if (data.SharePointType == SharePointType.Site && !string.IsNullOrEmpty(data.TargetPath))
                {
                    return string.Format("{0}/{1}", GeneratePath(node.Parent, flattenStructure), data.TargetPath);
                }
                else if (data.SharePointType == SharePointType.DocLibrary && !string.IsNullOrEmpty(data.TargetPath))
                {
                    return string.Format("{0}/{1}", GeneratePath(node.Parent, flattenStructure), data.TargetPath);
                }
                else
                {
                    return string.Format("{0}/{1}", GeneratePath(node.Parent, flattenStructure), node.Text);
                }
            }
            else
            {
                if (data.SharePointType != SharePointType.Application)
                {
                    return node.Text;
                }
                else
                {
                    return string.Empty;
                }
            }
        }

        #endregion

        private int CalculateItemThresholdViolation(TreeNode node)
        {
            int value = 0;

            DataNode currDataNode = node.Tag as DataNode;

            if (currDataNode.SharePointType == SharePointType.DocLibrary)
            {
                #region InLibrary
                foreach (TreeNode child in node.Nodes)
                {
                    var data = child.Tag as DataNode;

                    if (data.SharePointType == SharePointType.Document ||
                        data.SharePointType == SharePointType.Item)
                    {
                        value++;
                    }
                    else
                    {
                        //value++;
                        CalculateItemThresholdViolation(child);
                    }
                }

                if (value > ListItemThreshold)
                {
                    currDataNode.ItemThresholdExceededCount = 1;
                    value = 1;
                    currDataNode.GovernanceViolation = true;
                    currDataNode.ViolationType |= ViolationType.ItemThresholdExceeded;
                    //if (currDataNode.GovernanceViolation)
                    //{
                    //currDataNode.ExcludeableFromMigration = true;
                    //}

                    //if (coloring)
                    //{
                    //    if (currDataNode.Deletable == false)
                    //    {
                    //        node.ForeColor = Color.Red;
                    //    }
                    //    else
                    //    {
                    //        node.ForeColor = Color.DarkRed;
                    //    }
                    //}
                }
                else
                {
                    value = 0;
                }
#endregion
            }
            else
            {
                foreach (TreeNode child in node.Nodes)
                {
                    value += CalculateItemThresholdViolation(child);
                }
                currDataNode.ItemThresholdExceededCount = value;

            }
            return value;
        }

        private long CalculateItemSizeExceededViolation(TreeNode node)
        {
            long value = 0;
            #region Recursive tree iteration
            foreach (TreeNode child in node.Nodes)
            {
                value += CalculateItemSizeExceededViolation(child);
            }

            DataNode currDataNode = node.Tag as DataNode;

            if (currDataNode != null)
            {
                if (currDataNode.FileSize > FileSizeLimit)
                {
                    value++;
                    currDataNode.GovernanceViolation = true;
                    currDataNode.ViolationType |= ViolationType.ItemSizeExceeded;

                    //if (currDataNode.GovernanceViolation)
                    //{
                    //    currDataNode.ExcludeableFromMigration = true;
                    //}
                }
                currDataNode.ItemSizeExceededCount = (int)value;
            }

            return value;
            #endregion
        }

        private bool CalculatePathLengthExceededViolation(TreeNode node, int parentPathLength, bool flattenStructure)
        {
            bool value = false;

            #region Recursive tree iteration

            DataNode currDataNode = node.Tag as DataNode;

            if (currDataNode != null)
            {
                flattenStructure = flattenStructure || currDataNode.SharePointType == SharePointType.DocLibrary && currDataNode.RemoveFolderStructure;

                if (!(ExcludeSiteCollectionNamesInPathCalulation && (currDataNode.SharePointType == SharePointType.Application || currDataNode.SharePointType == SharePointType.SiteCollection)))
                {
                    if (currDataNode.SharePointType == SharePointType.SiteCollection ||
                        currDataNode.SharePointType == SharePointType.Site ||
                        currDataNode.SharePointType == SharePointType.DocLibrary)
                    {
                        if (string.IsNullOrEmpty(currDataNode.TargetPath))
                        {
                            parentPathLength += currDataNode.Title.Replace(" ","%20").Length;
                        }
                        else
                        {
                            parentPathLength += currDataNode.TargetPath.Replace(" ","%20").Length;
                        }
                    }
                    else
                    {
                        if (flattenStructure)
                        {
                            if (currDataNode.SharePointType != SharePointType.Folder)
                            {
                                parentPathLength += currDataNode.Title.Replace(" ","%20").Length;
                            }
                        }
                        else
                        {
                            parentPathLength += currDataNode.Title.Replace(" ","%20").Length;
                        }
                    }

                    currDataNode.PathLength = parentPathLength;

                    if (parentPathLength > PathLenghtLimit)
                    {
                        value = true;
                        currDataNode.GovernanceViolation = true;
                        currDataNode.ViolationType |= ViolationType.PathLengthExceeded;

                        //if (currDataNode.GovernanceViolation)
                        //{
                        //    currDataNode.ExcludeableFromMigration = true;
                        //}
                    }
                }

                //if (currDataNode.SharePointType == SharePointType.SiteCollection && !string.IsNullOrEmpty(currDataNode.TargetPath))
                //{
                //    parentPathLength = currDataNode.TargetPath.Length;
                //}

                foreach (TreeNode child in node.Nodes)
                {
                    // plus 1, / not in title included
                    if (CalculatePathLengthExceededViolation(child, parentPathLength + 1, flattenStructure))
                    {
                        value = true;
                    }
                }
            }
            return value;
            #endregion
        }

        private void ResetViolationChecks(TreeNode node)
        {
            foreach (TreeNode child in node.Nodes)
            {
                ResetViolationChecks(child);
            }

            DataNode data = node.Tag as DataNode;

            data.GovernanceViolation = false;
            data.GovernanceViolationCollected = 0;
            data.ItemSizeExceededCount = 0;
            data.ItemThresholdExceededCount = 0;
            data.SharePointStructureViolation = false;
            data.SharePointStructureViolationCollected = 0;
            data.ViolationType = ViolationType.NoViolation;
            data.PathLength = 0;
            data.DuplicatedFilenameViolationCount = 0;

            _flattenFileList.Clear();
        }

        private int SetViolationStates(TreeNode node)
        {
            int value = 0;
            DataNode data = node.Tag as DataNode;

            foreach (TreeNode child in node.Nodes)
            {
                data.GovernanceViolationCollected += SetViolationStates(child);
            }
            value = data.GovernanceViolationCollected;

            //  if a violation occurs in the node self
            //data.GovernanceViolation = data.ItemSizeExceededCount > 0 || data.ItemThresholdExceededCount > 0;

            if (data.GovernanceViolation)
            {
                value++;
            }

            //if (data.GovernanceViolation || value > 0)
            //{
            //    //if (data == null || data.Deletable == false)
            //    //{
            //    node.ForeColor = Color.Blue;
            //    //}
            //    //else
            //    //{
            //    //    node.ForeColor = Color.DarkRed;
            //    //}
            //}

            return value;
        }

        #endregion
    }
}
